/**
 * 微信SDK
 async loginAction() {
    const data = this.post()
    yy.log.debug('post data',data)
    const WX = this.service('wxapp', 'common')
    let d = await WX.wxLoginDecrypt(data)
    if (d) {
      d.ip = this.ctx.ip.indexOf('::ffff:') > -1 ? this.ctx.ip.replace('::ffff:', '') : this.ctx.ip
      const MEMBER = this.service('member', 'wxapp')
      const JWT = this.service('jwt', 'common')
      let user = await MEMBER.addAndUpdateMember(d)
      if (user) {
        user = await MEMBER.getUserByOpenId(d.openId)
        d.token = await JWT.encrypt(user)
        delete d.openId
        // delete d.ip
      }
    }
    this.success(d)
  }
 */
const wxCommon = require('./wx_common')
const config = think.config('wxapp')
var crypto = require('crypto')

function WXBizDataCrypt (appId, sessionKey) {
  this.appId = appId
  this.sessionKey = sessionKey
}

WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
  // base64 decode
  var sessionKey = new Buffer(this.sessionKey, 'base64')
  encryptedData = new Buffer(encryptedData, 'base64')
  iv = new Buffer(iv, 'base64')
  try {
    // 解密
    var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
    // 设置自动 padding 为 true，删除填充补位
    decipher.setAutoPadding(true)
    var decoded = decipher.update(encryptedData, 'binary', 'utf8')
    decoded += decipher.final('utf8')

    decoded = JSON.parse(decoded)
  } catch (err) {
    yy.log.error('WXBizDataCrypt', err)
    throw new Error('Illegal Buffer')
  }

  if (decoded.watermark.appid !== this.appId) {
    throw new Error('Illegal Buffer')
  }

  return decoded
}

module.exports = class extends wxCommon {
  /**
   * 通过code换取会话密钥session_key
   * @param code 用户授权后获得的code
   * 返回参数
      openid	用户唯一标识
      session_key	会话密钥
      unionid	用户在开放平台的唯一标识符。本字段在满足一定条件的情况下才返回。具体参看UnionID机制说明
   */
  async getSessionKeyByCode (code) {
    const url = 'https://api.weixin.qq.com/sns/jscode2session'
    const map = {
      appid: config.appId,
      secret: config.appSecret,
      js_code: code,
      grant_type: 'authorization_code'
    }
    yy.log.debug(`getSessionKeyByCode`, code)
    const d = await yy.http.get(url, map)
    return d
  }
  /**
   * 解析所有微信小程序 信息
   * @param {*} sessionKey
   * @param {*} iv
   * @param {*} encryptedData
   */
  wxDecrypt (sessionKey, iv, encryptedData) {
    const wx = new WXBizDataCrypt(config.appId, sessionKey)
    try {
      return wx.decryptData(encryptedData, iv)
    } catch (e) {
      return false
    }
  }
  /**
   * 微信小程序登录数据解密
   * @param data 微信小程序登录数据
   */
  async wxLoginDecrypt (d) {
    const sessionKey = await this.getSessionKeyByCode(d.code)
    if (sessionKey.errcode) {
      return false
    }
    try {
      // 解密
      const pc = new WXBizDataCrypt(config.appId, sessionKey.session_key)
      const member = pc.decryptData(d.encryptedData, d.iv)
      member.sessionKey = sessionKey.session_key
      if (sessionKey.unionid)member.unionid = sessionKey.unionid
      // 验证水印是否正确
      if (member.watermark.appid !== config.appId) {
        yy.log.error(`appId error, appId: ${config.appId}, watermark.appid: ${member.watermark.appid}`)
        return false
      }
      delete member.watermark
      return member
    } catch (err) {
      yy.log.error(err)
      return false
    }
  }

  /**
   * 发送模板消息
   * @param touser 接收者的openId
   * @param templateId 所需下发的模板消息的id
   * @param data 模板内容，不填则下发空模板
   * @param formId 表单提交场景下，为 submit 事件带上的 formId；支付场景下，为本次支付的 prepay_id
   * @param page 跳转的页面
   * @param color 模板内容字体的颜色，不填默认黑色
   * @param emphasisKeyword 模板需要放大的关键词，不填则默认无放大
   */
  async sendTemplateMessage (touser, templateId, data, formId, page = '', color = '#000000', emphasisKeyword = '') {
    const accessToken = await this.getWxAppAccessToken()
    const url = `https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=${accessToken}`

    const post = {
      touser,
      template_id: templateId,
      data,
      form_id: formId,
      page,
      color,
      emphasis_keyword: emphasisKeyword
    }
    // yy.log.info(`send template message post:`, JSON.stringify(post))
    const d = await yy.http.post(url, post)
    yy.log.info(`send template message response:`, JSON.stringify(d))
    return d
  }
}
